﻿using System;
using System.Collections.Generic;
using System.Text;
using Draco.DB.ORM.Schema.Dbml;
using Draco.DB.ORM.Mapping;
using Draco.DB.ORM.Mapping.AttrMapping;
using Draco.DB.ORM.Schema;
using Draco.DB.QuickDataBase.Schema;

namespace Draco.DB.ORM.Generator
{
    /// <summary>
    /// 实体类代码生成器
    /// </summary>
    public class EntityCodeGenerator
    {
        /// <summary>
        /// 文档注释头
        /// </summary>
        public const string CommentHeadTemplate =
@"//------------------------------------------------------------------------------
// <auto-generated>
//     此代码由工具生成。
//     运行库版本:2.0.50727.3053
//
//     对此文件的更改可能会导致不正确的行为，并且如果
//     重新生成代码，这些更改将丢失。
//     
//     创建时间:{0}
// </auto-generated>
//------------------------------------------------------------------------------";
        /// <summary>
        /// using部分
        /// </summary>
        public const string Using =//using
 @"using System;
using Draco.DB.ORM.Common;
using Draco.DB.ORM.Mapping;
using Draco.DB.ORM.Mapping.AttrMapping;";
        /// <summary>
        /// 主体模板
        /// </summary>
        public const string CSharpTemplate = "" +//主体模板
@"{0}
{1}
namespace {2}
{{
{3}
{4}
}}";
        /// <summary>
        /// class模板
        /// </summary>
        public const string ClassTemplate = "" +
@"    /// <summary>
    /// {0}
    /// </summary>
    [TableMapping({1})]
    public partial class {2} : AbstractEntity
    {{
{3}
{4}
{5}
{6}
    }}";
        /// <summary>
        /// 表名称属性模板
        /// </summary>
        public const string TableNameProperty = "" +
@"        
        /// <summary> 
        /// {0}
        /// </summary>
        public static string TableName
        {{
            get{{ return {1};}}
        }}";
        /// <summary>
        /// 字段模板
        /// </summary>
        public const string FieldTemplate = "" +
@"        private {0} {1};";

        /// <summary>
        /// 构造方法模板
        /// </summary>
        public const string ConstructTemplate = "" +
@"
        /// <summary> 
        /// 无参构造
        /// </summary>
        public {0}() {{ }}";

        /// <summary>
        /// 属性模板
        /// </summary>
        public const string PropertyTemplate = "" +
@"          
        /// <summary> 
        /// {0}
        /// </summary>
        {1}
        public {2} {3}
        {{
            get {{ return {4}; }}
            set
            {{
                {5} = value;
                OnPropertyChanged({6}, value);
            }}
        }}";

        /// <summary>
        /// Attribute模板
        /// </summary>
        public const string PropertyAttribute = "[{0}({1})]";
        /// <summary>
        /// 数据库对象
        /// </summary>
        protected Database m_Database;

        /// <summary>
        /// 代码构成
        /// </summary>
        protected string m_Using;
        /// <summary>
        /// 命名空间
        /// </summary>
        protected string m_Namespace;


        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="dataBase">数据库构架</param>
        public EntityCodeGenerator(Database dataBase)
        {
            m_Database = dataBase;
        }

        /// <summary>
        /// 构造c#实体类代码
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="PKGenerator"></param>
        /// <returns></returns>
        public virtual string GenerateCode(string tableName, String PKGenerator)
        {
            return GenerateCode(tableName, PKGenerator,false);
        }

        /// <summary>
        /// 构造c#实体类代码
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="PKGenerator"></param>
        /// <param name="GenerateDAO"></param>
        /// <returns></returns>
        public virtual string GenerateCode(string tableName, String PKGenerator,bool GenerateDAO)
        {
            if (m_Database == null || m_Database.Table == null)
                return "";
            Table TargetTable = null;
            foreach (var tbl in m_Database.Table)
            {
                if (String.Compare(tbl.Name, tableName, true) == 0)
                {
                    TargetTable = tbl;
                    break;
                }
            }
            return GenerateCSharpCode(TargetTable, PKGenerator, GenerateDAO);
        }

        /// <summary>
        /// 构造代码
        /// </summary>
        /// <param name="table"></param>
        /// <param name="PKGenerator"></param>
        /// <param name="GenerateDAO"></param>
        /// <returns></returns>
        protected virtual string GenerateCSharpCode(Table table, String PKGenerator, bool GenerateDAO)
        {
            if (table != null)
            {
                string CommentHead = String.Format(CommentHeadTemplate,DateTime.Now);
                string NameSpace = m_Database.EntityNamespace;
                string ClassCode = GenerateClass(table, PKGenerator);
                string DAOCode = GenerateDAO ? GenerateDAOCode(table) : "";//DAO
                string CSCode = string.Format(CSharpTemplate, CommentHead, Using, NameSpace, ClassCode, DAOCode);
                return CSCode;
            }
            return null;
        }

        /// <summary>
        /// 构造Class类
        /// </summary>
        /// <param name="table"></param>
        /// <param name="PKGenerator"></param>
        /// <returns></returns>
        protected virtual string GenerateClass(Table table, String PKGenerator)
        {
            string ClassComment = "映射实体类:"+table.Name;
            string AttributeText = GenerateClassAttribute(table, PKGenerator);
            string ClassName = GenerateClassName(table);
            string FieldsCode = GenerateFields(table.Type.Columns);
            string PropertiesCode = GenerateProperties(table.Type.Columns);
            string ConstructCode = String.Format(ConstructTemplate, ClassName);
            string StaticTableName = String.Format(TableNameProperty,"表名称:"+table.Name, "\"" + table.Name+"\"");
            string ClassCode = String.Format(ClassTemplate, ClassComment, AttributeText, ClassName, StaticTableName,FieldsCode, ConstructCode, PropertiesCode);
            return ClassCode;
        }
        /// <summary>
        /// 构造一个表属性
        /// </summary>
        /// <param name="table"></param>
        /// <param name="PKGenerator"></param>
        /// <returns></returns>
        protected virtual string GenerateClassAttribute(Table table, String PKGenerator)
        {
            TableMappingAttribute Attribute = new TableMappingAttribute();
            Attribute.TypeName = GenerateClassName(table);
            Attribute.IsTable = true;
            Attribute.TableName = table.Name;
            Attribute.KeyGenerator = PKGenerator;
            return Attribute.ToString();
        }
        /// <summary>
        /// 构造所有私有变量
        /// </summary>
        /// <param name="Columns"></param>
        /// <returns></returns>
        protected virtual string GenerateFields(ISimpleList<Column> Columns)
        {
            StringBuilder sBuilder = new StringBuilder();
            if (Columns != null)
            {
                foreach (var Col in Columns)
                {
                    GenerateField(sBuilder, Col);
                }
            }
            return sBuilder.ToString();
        }
        /// <summary>
        /// 构造一个私有变量
        /// </summary>
        /// <param name="sBuilder"></param>
        /// <param name="Col"></param>
        /// <returns></returns>
        protected virtual void GenerateField(StringBuilder sBuilder,Column Col)
        {
            string TypeString = GetTypeString(Col.Type);
            sBuilder.Append(String.Format(FieldTemplate, TypeString, GenerateStorageName(Col)));
            sBuilder.Append("\r\n");
        }
        /// <summary>
        /// 构造所有公有属性
        /// </summary>
        /// <param name="Columns"></param>
        /// <returns></returns>
        protected virtual string GenerateProperties(ISimpleList<Column> Columns)
        {
            StringBuilder sBuilder = new StringBuilder();
            if (Columns != null)
            {
                foreach (var Col in Columns)
                {
                    GenerateProperty(sBuilder, Col);
                }
            }
            return sBuilder.ToString();
        }
        /// <summary>
        /// 构造一个公有属性
        /// </summary>
        /// <param name="sBuilder"></param>
        /// <param name="Col"></param>
        /// <returns></returns>
        protected virtual void GenerateProperty(StringBuilder sBuilder, Column Col)
        {
            string Comment = Col.Comment;
            if(String.IsNullOrEmpty(Comment))
                Comment = "公有属性:" + Col.Member + ",字段名称：" + Col.Name;
            string TypeString = GetTypeString(Col.Type);
            string PropertyName = GeneratePropertyName(Col);
            string PropertyString = "\"" + PropertyName + "\"";
            string FieldName = GenerateStorageName(Col);
            string AttributeText = GeneratePropertyAttribute(Col);
            string PropertyCode = String.Format(PropertyTemplate, Comment, AttributeText, TypeString, PropertyName, FieldName, FieldName, PropertyString);
            sBuilder.Append(PropertyCode);
        }

        /// <summary>
        /// 构造一个属性的属性
        /// </summary>
        /// <param name="Col"></param>
        /// <returns></returns>
        protected virtual string GeneratePropertyAttribute(Column Col)
        {
            if (Col.IsPrimaryKey)
            {
                PrimaryKeyMappingAttribute Attribute = new PrimaryKeyMappingAttribute();
                Attribute.ColumnName = Col.Name;
                Attribute.PropertyName = GeneratePropertyName(Col);
                Attribute.FieldType = DataTypeConvert.ConvertToFieldType((ADOType)Col.ADOType);
                Attribute.FieldLength = (int)Col.FieldLength;
                Attribute.Remark = Col.Comment;
                return String.Format(PropertyAttribute, "PrimaryKeyMapping", Attribute.ToString());
            }
            else
            {
                FieldMappingAttribute Attribute = new FieldMappingAttribute();
                Attribute.ColumnName = Col.Name;
                Attribute.PropertyName = GeneratePropertyName(Col);
                Attribute.FieldType = DataTypeConvert.ConvertToFieldType((ADOType)Col.ADOType);//
                Attribute.IsNullable = Col.CanBeNull;
                Attribute.FieldLength = (int)Col.FieldLength;
                Attribute.DefauleValue = Col.Expression;
                Attribute.Remark = Col.Comment;
                return String.Format(PropertyAttribute, "FieldMapping", Attribute.ToString());
            }
        }

        /// <summary>
        /// 构造DAO代码
        /// </summary>
        /// <param name="table">表对象</param>
        /// <returns></returns>
        protected virtual string GenerateDAOCode(Table table)
        {
            const String DAOTemplate = ""+
@"
    /// <summary>
    /// {0}的DAO
    /// </summary>
    public partial class DAO4{0} : EntityHandler<{0}>
    {{
        ///<summary>
        ///构造DAO
        ///</summary>
        /// <param name='entity'>实体</param>
        /// <param name='handler'>操作接口</param>
        public DAO4{0}({0} entity, Draco.DB.QuickDataBase.IDataBaseHandler handler)
            :base(entity,handler)
        {{
        }}
    }}";
            return String.Format(DAOTemplate, GenerateClassName(table));
        }

        #region 
        /// <summary>
        /// 获取类型字符串
        /// </summary>
        /// <param name="Type"></param>
        /// <returns></returns>
        protected virtual string GetTypeString(string Type)
        {
            if (!String.IsNullOrEmpty(Type))
            {
                int index = Type.LastIndexOf(".");
                if (index > 0)
                    Type = Type.Substring(index + 1);
                return Type;
            }
            return "UNKNOWN_Type";
        }
        /// <summary>
        /// 生成类名称
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        protected virtual string GenerateClassName(Table table)
        {
            if(table!=null)
                return table.Name.ToUpper();
            return "";
        }

        /// <summary>
        /// 生成属性名称
        /// </summary>
        /// <param name="Col"></param>
        /// <returns></returns>
        protected virtual string GeneratePropertyName(Column Col)
        {
            if(Col!=null)
                return Col.Member;
            return "";
        }
        /// <summary>
        /// 生成属性对应的私有成员名称
        /// </summary>
        /// <param name="Col"></param>
        /// <returns></returns>
        protected virtual string GenerateStorageName(Column Col)
        {
            if (Col != null)
                return "_" + Col.Member;
            return "";
        }
        #endregion
    }
}
